# -*- coding: utf-8 -*-

import os
import json
import socket
import threading
import uuid
import time
from log import getLogger
from check import clien_reg, check_hart
from pipeline import Pipeline
import traceback

logger = getLogger(__name__)


class Server(object):

    coded_format = 'utf-8'  # 处理消息编码格式

    def __init__(self):
        # 构造套接字
        self.__socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.__clien_list = {}  # 客户端
        self.__urc_sn = {}  # 用户设备关系绑定
        self.pipeline = Pipeline()

    def send_json(self, conn, code, msg, data=None):
        d = dict()
        d['code'] = code
        d['msg'] = msg
        if data:
            d['data'] = data
        else:
            d['data'] = ''
        try:
            conn.sendall(json.dumps(d).encode(self.coded_format))
        except:
            pass

    def message_handle(self, user_uuid):
        """
        用户子线程 处理消息
        """
        conn = self.__clien_list[user_uuid]['conn']
        while True:
            try:
                buffer = conn.recv(1024).decode(self.coded_format)
                obj = json.loads(buffer)
                logger.info(obj)
                if obj['cmd'] == 'heartbeat':
                    clien_reg(user_uuid, obj['sn'])

                    self.send_json(conn, 1, 'ok')
                else:
                    self.send_json(conn, -1, '消息类型错误')

            except json.decoder.JSONDecodeError:
                self.send_json(conn, -1, 'The data format is not json')
            except AttributeError:
                self.send_json(conn, -1, 'error')
            except Exception as e:
                logger.warning("连接失败：" + user_uuid + str(e))
                del self.__clien_list[user_uuid]
                # del self.__hart_list[user_uuid]
                conn.close()
                break

    def ws_callback(self, msg):
        """
        接收ws服务器传递的消息回调
        """
        try:
            logger.info(msg)
            obj = json.loads(msg)
            if obj['cmd'] == 'ssh':
                user_uuid = self.__urc_sn[obj['sn']]  # 通过设备SN取出客户端uuid
                self.broadcast(user_uuid, obj)
        except Exception:
            logger.error(traceback.format_exc())
        # self.pipeline.receiving_send(msg)

    def broadcast(self, user_uuid, message):
        """
        消息广播
        """
        conn = self.__clien_list[user_uuid]['conn']
        # self.send_json(conn, 0, message)
        conn.sendall(json.dumps(message).encode(self.coded_format))

    def start(self):
        """
        启动服务器
        """
        logger.info('System up and running...')
        # 绑定端口
        self.__socket.bind(('', 8881))
        # 启动监听
        self.__socket.listen(5)

        # 启动管道线程
        #self.pipeline.creation_pipe()
        threading.Thread(target=self.pipeline.receiving_loop,
                         args=(self.ws_callback, )).start()

        # 启动一个检查心跳状态线程
        threading.Thread(target=check_hart, args=(), name="check_hart").start()
        # 开始监听
        while True:
            conn, addr = self.__socket.accept()
            logger.info('Connected by' + str(addr))
            try:
                buffer = conn.recv(1024).decode(self.coded_format)
                sole_uuid = str(uuid.uuid4()).upper()
                obj = json.loads(buffer)
                logger.info(obj)

                # 客户端登录
                if obj['cmd'] == 'login' and obj['sn']:
                    self.__clien_list[sole_uuid] = {"conn": conn}
                    self.__urc_sn[obj['sn']] = sole_uuid

                    # 发送uuid到客户端
                    conn.sendall(
                        json.dumps({
                            'uuid': sole_uuid
                        }).encode(self.coded_format))

                    t = threading.Thread(target=self.message_handle,
                                         args=(sole_uuid, ))
                    t.setDaemon(True)
                    t.start()
                else:
                    logger.info('参数出错')
            except Exception as e:
                logger.warning(e)


if __name__ == "__main__":

    server = Server()
    server.start()
